/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package parserxml;

import java.io.*;
import java.util.*;
import org.exolab.castor.xml.dtd.parser.*;
import org.exolab.castor.xml.dtd.*;

/**
 */
public class GeneradorTablas {
  //Lista global con todas las tablas generadas a partir del DTD.

  HashMap<String, TablaSQL> tablasSQL;
  HashMap<String, RelacionER> relacionesER;
  DTDdocument dtd;

  public void GeneradorTablas() {
    this.tablasSQL = new HashMap<String, TablaSQL>();
    this.relacionesER = new HashMap<String, RelacionER>();
  }

  public void generar(String dtd_file) throws Exception {

    FileInputStream inputStream = new FileInputStream(dtd_file);
    InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
    InputCharStream charStream = new InputCharStream(reader);
    DTDParser parser = new DTDParser(charStream);
    dtd = parser.Input(); //Esta es la llamada que parsea el archivo

    Element raiz = dtd.getElement("database");
    if (raiz == null) {
      // TODO generar error, no hay tag databaser
      return;
    }
    if (!raiz.isElemOnlyContent()) {
      // TODO generar error, la raiz debe contener solo elementos
      return;
    }

    ContentParticle raizCont = raiz.getContent();
    if (raizCont.isSeqType()) {
      procesarHijosRaiz(raizCont.getChildren());
    } else if (raizCont.isReferenceType()) {
      // la raiz contiene una secuencia de elementos
      procesarElemento(dtd.getElement(raizCont.getReference()));
    } else {
      // TODO error, la raiz solo puede ser secuencia o referencia
    }
  }

  private void procesarHijosRaiz(Enumeration hijosRaiz) {
    ContentParticle contentHijo;
    while (hijosRaiz.hasMoreElements()) {
      contentHijo = (ContentParticle) hijosRaiz.nextElement();
      if (contentHijo.isReferenceType()) {
        // proceso el elemento del dtd que se llame como el content
        Element hijo = dtd.getElement(contentHijo.getReference());
        if (tieneAtributoId(hijo)) {
          // element es entidad porque tiene un atributo como id
          procesarEntidad(hijo);
        } else {
          // elemento debe ser relacion
          procesarRelacion(hijo);
        }
      } else {
        //TODO error, los hijos de la raiz solo pueden ser una secuencia
      }
    }
  }

  private void procesarRelacion(Element e) {

    if (!e.isElemOnlyContent()) {
      // TODO error, la relacion debe contener elementos hijos
      return;
    }

    ContentParticle cp = e.getContent();
    if (!cp.isSeqType()) {
      // TODO error, la relacion debe contener al menos de elementos hijos
      return;
    }

    Enumeration hijosRel = cp.getChildren();
    ContentParticle contentHijo;
    while (hijosRel.hasMoreElements()) {
      contentHijo = (ContentParticle) hijosRel.nextElement();
      
      if (!contentHijo.isReferenceType()) {
        //TODO error, los hijos de la raiz solo pueden ser una secuencia
        return;
      }
      Element hijo = dtd.getElement(contentHijo.getReference());
      if (tieneAtributoId(hijo)) {
        // el hijo es una relacion
      } else {
        // el hijo es un atributo de la relacion
      }
      
    }
  }

  private void procesarEntidad(Element entidad) {

    TablaSQL tablaEntidad = new TablaSQL(entidad.getName());
    tablasSQL.put(entidad.getName(), tablaEntidad);

    // agrego los atributos de ATTLIST
    procesarAttlist(entidad.getAttributes(), tablaEntidad);

    if (entidad.isElemOnlyContent()) {
//      procesarContenido()
    } else if (entidad.isMixedContent()) {
      // la entidad contiene pcdata
      tablaEntidad.addAtributo(entidad.getName(), Boolean.FALSE);
    }
  }

  /**
   * 
   * @return true si el elemento e tiene id.
   */
  private boolean tieneAtributoId(Element e) {
    Attribute attribute;

    Enumeration<Attribute> attributes = e.getAttributes();
    while (attributes.hasMoreElements()) {
      attribute = attributes.nextElement();

      if (attribute.isIDType()) {
        return true;
      }
    }
    return false;
  }

  private void procesarAttlist(Enumeration attributes, TablaSQL tablaSQL) {
    Attribute attr;

    while (attributes.hasMoreElements()) {
      attr = (Attribute) attributes.nextElement();

      if (attr.isIDType()) {
        // el atributo es la clave
        tablaSQL.addClavePK(attr.getName());

      } else if (attr.isStringType()) {
        // el atributo no es clave
        if (attr.isREQUIRED()) {
          tablaSQL.addAtributo(attr.getName(), Boolean.TRUE);
        } else if (attr.isIMPLIED()) {
          tablaSQL.addAtributo(attr.getName(), Boolean.FALSE);
        } else {
          // TODO error, el valor del atributo solo puede ser REQUIRED o IMPLIED
        }
      } else {
        // TODO error, el atributo solo puede ser de tipo ID o CDATA
      }
    }
  }
}
